<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 判断js数据类型的方法有四种：

        // 1、typeOf
        // 一般用于判断基本的数据类型，null 除外，判断 null 会返回 object；
        // 还可以判断引用数据类型中的 函数，返回 function

        // console.log(typeof 1)  // number
        // console.log(typeof '1') // string
        // console.log(typeof true)  // boolean
        // console.log(typeof undefined)  // undefined
        // console.log(typeof null) // object
        // console.log(typeof Symbol(1)) // symbol
        // console.log(typeof NaN) // number

        // console.log(typeof {})  // object
        // console.log(typeof [])  // object
        // console.log(typeof function () { }) // function

        // 2、instance  of
        // 一般用于判断引用的数据类型，判断引用数据类型返回 true，判断基本数据类型返回 false

        // console.log([] instanceof Array) // true
        // console.log({} instanceof Object)// true

        // console.log(1 instanceof Number)// false
        // console.log('' instanceof String)// false
        // console.log(true instanceof Boolean)// false

        // 3、constructor
        // 一般的数据类型和引用的都可以判断，但是 undefined 和 null 除外

        // console.log((1).constructor == Number)
        // console.log(('').constructor == String)
        // console.log((true).constructor == Boolean)
        // console.log(({}).constructor == Object)
        // console.log(([]).constructor == Array)

        // console.log((undefined).constructor == undefined)
        // console.log((null).constructor == null)
        //没有构造器，会报错

        // 4、Object.prototype.toString.call() 可以判断任何数据类型
        Object.prototype.toString({}) // "[object Object]"
        Object.prototype.toString.call({}) // 同上结果，加上call也ok
        Object.prototype.toString.call(1) // "[object Number]"
        Object.prototype.toString.call('1') // "[object String]"
        Object.prototype.toString.call(true) // "[object Boolean]"
        Object.prototype.toString.call(function () { }) // "[object Function]"
        Object.prototype.toString.call(null) //"[object Null]"
        Object.prototype.toString.call(undefined) //"[object Undefined]"
        Object.prototype.toString.call(/123/g) //"[object RegExp]"
        Object.prototype.toString.call(new Date()) //"[object Date]"
        Object.prototype.toString.call([]) //"[object Array]"
        Object.prototype.toString.call(document) //"[object HTMLDocument]"
        Object.prototype.toString.call(window) //"[object Window]"



        // 实现一个全局通用的数据类型判断方法
        function getType(obj) {
            let type = typeof obj
            if (type !== 'object') {
                // 先进行typeof判断，如果是基础数据类型，直接返回
                return type
            }
            // 对于typeof返回结果是object的，再进行如下的判断，正则返回结果
            return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1')
        }

        // 用法：
        getType([]) // "Array" typeof []是object，因此toString返回
        getType('123') // "string" typeof 直接返回
        getType(window) // "Window" toString返回
        getType(null) // "Null"首字母大写，typeof null是object，需toString来判断
        getType(undefined) // "undefined" typeof 直接返回
        getType() // "undefined" typeof 直接返回
        getType(function () { }) // "function" typeof能判断，因此首字母小写
        getType(/123/g) //"RegExp" toString返回

        console.log(getType(undefined));
    </script>
</body>

</html>